﻿using Newtonsoft.Json.Linq;

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;

using Rectangle = System.Drawing.Rectangle;
using StbImageSharp;
using System.Threading;

namespace TexPacker
{
    class NamedImage
    {
        public string name;
        public CutImage image;
        public Rectangle uv;
    }

    public static class PackTool
    {
        public static string[] GetAllPics(string folder)
        {
            var pngs = System.IO.Directory.GetFiles(folder, "*.png", System.IO.SearchOption.AllDirectories);
            return pngs;
        }
        //public static ttlib.PicOption? LoadPicOption(string filename)
        //{
        //    var _path = System.IO.Path.GetDirectoryName(filename);
        //    var _filename = System.IO.Path.GetFileNameWithoutExtension(filename);
        //    var _ext = System.IO.Path.GetExtension(filename).ToLower();
        //    if (_ext == ".png" || _ext == ".jpg" || _ext == ".jpeg")
        //    {
        //        _ext += ".json";
        //    }
        //    var opfile = System.IO.Path.Combine(_path, _filename + _ext);
        //    if (System.IO.File.Exists(opfile))
        //    {
        //        try
        //        {
        //            var txt = System.IO.File.ReadAllText(opfile);
        //            var json = JObject.Parse(txt);
        //            return ttlib.PicOption.FromJson(json);
        //        }
        //        catch (Exception err)
        //        {
        //            return null;
        //        }
        //    }
        //    else
        //    {
        //        return null;
        //    }
        //}

        static void SavePack(ttlib.ILogger logger, string path, OutPackImage image)
        {
            logger.Log("save at" + path);
            var picpath = System.IO.Path.Combine(path + ".png");

            image.Save(picpath);

        }
        public static void Pack(ttlib.ILogger logger, string folder, int packimgsize)
        {
            logger.Log("Start ImagePack");

            //load all Textures;
            var pics = GetAllPics(folder);

            int loadcount = 0;
            List<NamedImage> images = new List<NamedImage>();
            foreach (var f in pics)
            {
                using (var fs = System.IO.File.OpenRead(f))
                {
                    var result = StbImageSharp.ImageResult.FromStream(fs, StbImageSharp.ColorComponents.RedGreenBlueAlpha);
                    //var name = System.IO.Path.GetFileNameWithoutExtension(f);
                    images.Add(new NamedImage() { name = f, image = new CutImage(result) });

                    if (loadcount % 100 == 0)
                    {
                        logger.Log("begin Load AllTexts " + loadcount + "/" + pics.Length);
                    }
                    loadcount++;
                }
            }
            logger.Log("Load AllTexts done.");



            //图片按照尺寸排序
            images.Sort((a, b) =>
            {
                return (b.image.Height - a.image.Height) * 2048 + (b.image.Width - a.image.Width);
            });


            var outpath = System.IO.Path.GetDirectoryName(folder);
            var outname = System.IO.Path.GetFileName(folder);

            int outcount = 0;
            OutPackImage lastimg = null;
            OutPackImage outimage = null;
            TexPacker.MaxRectsBinPack binpack = null;

            foreach (var img in images)
            {
                if (outimage == null)
                {
                    outimage = new OutPackImage(packimgsize, packimgsize);
                    binpack = new TexPacker.MaxRectsBinPack(packimgsize, packimgsize, false);
                }
                img.uv = binpack.Insert(img.image.Width, img.image.Height, TexPacker.MaxRectsBinPack.FreeRectChoiceHeuristic.RectBestLongSideFit);
                if (img.uv.Height == 0)
                {
                    var outpicname = System.IO.Path.Combine(outpath, outname + "_pack" + outcount);

                    SavePack(logger, outpicname, outimage);


                    outcount++;
                    outimage = new OutPackImage(packimgsize, packimgsize);
                    binpack = new TexPacker.MaxRectsBinPack(packimgsize, packimgsize, false);
                    img.uv = binpack.Insert(img.image.Width, img.image.Height, TexPacker.MaxRectsBinPack.FreeRectChoiceHeuristic.RectBestLongSideFit);
                }
                var name = System.IO.Path.GetFileNameWithoutExtension(img.name);
                //var option = LoadPicOption(img.name);//border 重算，但是pivot 可以来自文件中
                //ttlib.PicOption op = option != null ? option.Value : new ttlib.PicOption();
                ttlib.PicOption op = new ttlib.PicOption();
                op.borderLeft = (uint)img.image.range.X;
                op.borderRight = (uint)(img.image.srcwidth - op.borderLeft - img.image.range.Width);
                op.borderTop = (uint)img.image.range.Y;
                op.borderBottom = (uint)(img.image.srcheight - op.borderTop - img.image.range.Height);
                //if (option == null)
                //{
                //    op.pivotX = img.image.srcwidth / 2;
                //    op.pivotY = img.image.srcheight / 2;
                //}
                outimage.SetImage(name, op, img.image, img.uv.X, img.uv.Y);


            }
            if (binpack.UsedRectangles.Count > 0)
            {
                var outpicname = System.IO.Path.Combine(outpath, outname + "_pack" + outcount);
                SavePack(logger, outpicname, outimage);

            }



        }

        public static void UnPack(ttlib.ILogger logger, string filename)
        {
            logger.Log("start unpack");
            var json = JObject.Parse(System.IO.File.ReadAllText(filename + ".json"));
            JArray sprites = json["sprites"] as JArray;
            var path = System.IO.Path.GetDirectoryName(filename);
            var outname = System.IO.Path.GetFileNameWithoutExtension(filename);
            var outpath = System.IO.Path.Combine(path, outname + "_unpack");
            if (System.IO.Directory.Exists(outpath) == false)
                System.IO.Directory.CreateDirectory(outpath);
            logger.Log("unpack to:" + outpath);
            using (var fs = System.IO.File.OpenRead(filename))
            {
                var result = StbImageSharp.ImageResult.FromStream(fs, StbImageSharp.ColorComponents.RedGreenBlueAlpha);
                var srcimage = new Image(result);
                foreach (var s in sprites)
                {
                    var name = s["name"];
                    var uv = s["uv"].ToString().Split(',');
                    var border = s["border"].ToString().Split(',');
                    int uvx = int.Parse(uv[0]);
                    int uvy = int.Parse(uv[1]);
                    int uvw = int.Parse(uv[2]);
                    int uvh = int.Parse(uv[3]);
                    int borderx1 = int.Parse(border[0]);
                    int bordery1 = int.Parse(border[1]);
                    int borderx2 = int.Parse(border[2]);
                    int bordery2 = int.Parse(border[3]);
                    var subdata = srcimage.SubImageData(uvx, uvy, uvw, uvh);
                    var outimage = new Image(borderx1 + borderx2 + uvw, bordery1 + bordery2 + uvh);
                    outimage.SetImageData(subdata, borderx1, borderx2, uvw, uvh);
                    var outunpackname = System.IO.Path.Combine(outpath, name + ".png");
                    outimage.Save(outunpackname);
                }
            }
            logger.Log("unpack done.");
        }
        public static void CutTex(ttlib.ILogger logger, string filename, int cutX, int cutY, bool cutBorder)
        {
            logger.Log("Ready to cut.");

            var name = System.IO.Path.GetFileNameWithoutExtension(filename);
            var outpath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(filename), "splittex", name);
            if (System.IO.Directory.Exists(outpath) == false)
            {
                System.IO.Directory.CreateDirectory(outpath);
            }
            var imgout = new StbImageWriteSharp.ImageWriter();


            using (var fs = System.IO.File.OpenRead(filename))
            {
                var result = StbImageSharp.ImageResult.FromStream(fs, StbImageSharp.ColorComponents.RedGreenBlueAlpha);
                var srcimage = new Image(result);
                var xcount = srcimage.Width / cutX;
                var ycount = srcimage.Height / cutY;
                for (var y = 0; y < ycount; y++)
                {
                    for (var x = 0; x < xcount; x++)
                    {
                        int itemwidth = cutX;
                        int itemheight = cutY;
                        byte[] itemrgba = null;

                        if (cutBorder)
                        {
                            var img = srcimage.SubImage(x * cutX, y * cutY, cutX, cutY);
                            itemrgba = img.datargba;
                            itemwidth = img.Width;
                            itemheight = img.Height;
                        }
                        else
                        {
                            itemrgba = srcimage.SubImageData(x * cutX, y * cutY, cutX, cutY);
                        }
                        var outfile = System.IO.Path.Combine(outpath, name + "_sp_" + x.ToString("d03") + "_" + y.ToString("d03") + ".png");
                        if (System.IO.File.Exists(outfile))
                            System.IO.File.Delete(outfile);
                        using (var sfs = System.IO.File.OpenWrite(outfile))
                        {
                            imgout.WritePng(itemrgba, itemwidth, itemheight, StbImageWriteSharp.ColorComponents.RedGreenBlueAlpha, sfs);
                        }
                    }
                }
            }
            logger.Log("  cut to:" + outpath);
        }
    }
}
